﻿using System;
using System.Net;
using System.Reflection;
using System.Linq.Expressions;

namespace SL8.SL.Helpers
{
    public static class LinqExpressionHelper
    {
        #region 获取包含表达式
        /// <summary>
        /// 获取包含表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameExpr"></param>
        /// <param name="protertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> GetContainsExpression<T>(ParameterExpression parameExpr, string protertyName, string value)
        {
            Expression nameExpr = Expression.Property(parameExpr, typeof(T), protertyName);
            MethodInfo methodInfo = (Methodof<Func<string, bool>>)"".Contains;
            Expression contains = Expression.Call(nameExpr, methodInfo, new Expression[] { Expression.Constant(value) });
            return Expression.Lambda<Func<T, bool>>(contains, new ParameterExpression[] { parameExpr });
        }

        public static LambdaExpression GetContainsExpressionByEntityType(ParameterExpression parameExpr, string protertyName, string value, Type entityType)
        {
            MethodInfo methodInfo = typeof(LinqExpressionHelper).GetMethod("GetContainsExpression");

            //Type funcType = typeof(Func<,>);
            //Type entityFuncType = funcType.MakeGenericType(entityType, typeof(bool));

            MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(entityType);
            return genericMethodInfo.Invoke(null, new object[] { 
            parameExpr,
            protertyName,
            value
            }) as LambdaExpression;
        }
        #endregion

        #region 获取相等比较表达式
        /// <summary>
        /// 获取相等比较表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameExpr"></param>
        /// <param name="protertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> GetEqualExpression<T>(ParameterExpression parameExpr, string protertyName, object value)
        {
            Expression nameExpr = Expression.Property(parameExpr, typeof(T), protertyName);
            ConstantExpression conRight = Expression.Constant(value, value.GetType());
            BinaryExpression binary = Expression.Equal(nameExpr, conRight);
            return Expression.Lambda<Func<T, bool>>(binary, new ParameterExpression[] { parameExpr });
        }

        public static LambdaExpression GetEqualExpressionByEntityType(ParameterExpression parameExpr, string protertyName, object value, Type entityType)
        {
            MethodInfo methodInfo = typeof(LinqExpressionHelper).GetMethod("GetEqualExpression");

            MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(entityType);
            return genericMethodInfo.Invoke(null, new object[] { 
            parameExpr,
            protertyName,
            value
            }) as LambdaExpression;
        }
        #endregion

        #region 获取大于等于表达式
        /// <summary>
        /// 获取大于等于表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameExpr"></param>
        /// <param name="protertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> GetGreaterThanOrEqualExpression<T>(ParameterExpression parameExpr, string protertyName, object value)
        {
            Expression nameExpr = Expression.Property(parameExpr, typeof(T), protertyName);

            if (LinqExpressionHelper.IsNullableType(nameExpr.Type))
            {
                Type srcType = nameExpr.Type.GetGenericArguments()[0];

                nameExpr = Expression.Convert(nameExpr, srcType);

                
            }

            ConstantExpression conRight = Expression.Constant(value, value.GetType());
            BinaryExpression binary = Expression.GreaterThanOrEqual(nameExpr, conRight);
            return Expression.Lambda<Func<T, bool>>(binary, new ParameterExpression[] { parameExpr });
        }

        public static LambdaExpression GetGreaterThanOrEqualExpressionByEntityType(ParameterExpression parameExpr, string protertyName, object value, Type entityType)
        {
            MethodInfo methodInfo = typeof(LinqExpressionHelper).GetMethod("GetGreaterThanOrEqualExpression");

            MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(entityType);
            return genericMethodInfo.Invoke(null, new object[] { 
            parameExpr,
            protertyName,
            value
            }) as LambdaExpression;
        }
        #endregion

        #region 获取小于等于表达式
        /// <summary>
        /// 获取小于等于表达式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameExpr"></param>
        /// <param name="protertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> GetLessThanOrEqualExpression<T>(ParameterExpression parameExpr, string protertyName, object value)
        {
         //   Expression nameExpr = Expression.Property(parameExpr, typeof(T), protertyName);
            Expression nameExpr = Expression.Property(parameExpr, typeof(T), protertyName);

            if (LinqExpressionHelper.IsNullableType(nameExpr.Type))
            {
                Type srcType = nameExpr.Type.GetGenericArguments()[0];

                nameExpr = Expression.Convert(nameExpr, srcType);


            }
            ConstantExpression conRight = Expression.Constant(value, value.GetType());
            BinaryExpression binary = Expression.LessThanOrEqual(nameExpr, conRight);
            return Expression.Lambda<Func<T, bool>>(binary, new ParameterExpression[] { parameExpr });
        }

        public static LambdaExpression GetLessThanOrEqualExpressionByEntityType(ParameterExpression parameExpr, string protertyName, object value, Type entityType)
        {
            MethodInfo methodInfo = typeof(LinqExpressionHelper).GetMethod("GetLessThanOrEqualExpression");

            MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(entityType);
            return genericMethodInfo.Invoke(null, new object[] { 
            parameExpr,
            protertyName,
            value
            }) as LambdaExpression;
        }
        #endregion

        /// <summary>
        /// 是否是可空类型
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static bool IsNullableType(Type t)
        {
            return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
        }
    }
}
